package com.reformer.commons.utils;

import com.alibaba.fastjson.annotation.JSONField;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 将对象的非String类型(除Date类型)转化为String类型；<br>
 * 将金额的单位转化为分；<br>
 * note：此方法会自动删除被transient修饰的字段和被@JSONField注解的字段
 *
 * @author sdc
 * @since 2.0
 */
public class ConvertUtils {
    public static Map<String, Object> fromObject(Object o) {
        if (o == null || o.getClass() == Object.class)
            return new HashMap<String, Object>();
        Map<String, Object> ret = new HashMap<String, Object>();
        if (o instanceof Collection) {
            return null;
        } else if (o instanceof Map) {
            Map map = (Map) o;
            for (Object key : map.keySet()) {
                Object value = map.get(key);
                if (key != null && value != null) {
                    if (value instanceof BigDecimal) {
                        ret.put(key.toString(), ((BigDecimal) value).multiply(new BigDecimal(100)).intValue() + "");
                    } else if (value instanceof Number || value instanceof Boolean || value instanceof Character) {
                        ret.put(key.toString(), value.toString());
                    } else if (value instanceof Collection) {
                        ret.put(key.toString(), fromCollection((Collection) value));
                    } else if (value.getClass().isArray()) {
                        ret.put(key.toString(), fromArray(value));
                    } else if (value instanceof Date || value instanceof String) {
                        ret.put(key.toString(), value);
                    } else {
                        ret.put(key.toString(), fromObject(value));
                    }
                }
            }
        } else {
            try {
                Class<?> clazz = o.getClass();
                BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
                PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
                for (int i = 0; i < descriptors.length; i++) {
                    String key = descriptors[i].getName();
                    try {
                        Field field = clazz.getDeclaredField(key);
                        // field.setAccessible(true);
                        if (Modifier.isTransient(field.getModifiers()))
                            continue;
                        JSONField jsonField = field.getAnnotation(JSONField.class);
                        if (jsonField != null && !jsonField.serialize())
                            continue;
                    } catch (Exception e) {
                    }
                    Object value = descriptors[i].getReadMethod().invoke(o);
                    if (key != null && value != null) {
                        if (value instanceof BigDecimal) {
                            ret.put(key.toString(), ((BigDecimal) value).multiply(new BigDecimal(100)).intValue() + "");
                        } else if (value instanceof Number || value instanceof Boolean || value instanceof Character) {
                            ret.put(key.toString(), value.toString());
                        } else if (value instanceof Collection) {
                            ret.put(key.toString(), fromCollection((Collection) value));
                        } else if (value.getClass().isArray()) {
                            ret.put(key.toString(), fromArray(value));
                        } else if (value instanceof Date || value instanceof String) {
                            ret.put(key.toString(), value);
                        } else {
                            ret.put(key.toString(), fromObject(value));
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    public static List<?> fromCollection(Collection col) {
        List ret = new LinkedList();
        for (Object o : col) {
            if (o == null)
                continue;
            if (o instanceof BigDecimal) {
                ret.add(((BigDecimal) o).multiply(new BigDecimal(100)).intValue() + "");
            } else if (o instanceof Number || o instanceof Boolean || o instanceof Character) {
                ret.add(o.toString());
            } else if (o instanceof Collection) {
                ret.add(fromCollection((Collection) o));
            } else if (o.getClass().isArray()) {
                ret.add(fromArray(o));
            } else if (o instanceof Date || o instanceof String) {
                ret.add(o);
            } else {
                ret.add(fromObject(o));
            }
        }
        return ret;
    }

    public static List<?> fromArray(Object array) {
        List ret = new LinkedList();
        Class clazz = array.getClass();
        for (int i = 0; i < Array.getLength(array); i++) {
            Object o = Array.get(array, i);
            if (o == null)
                continue;
            if (o instanceof BigDecimal) {
                ret.add(((BigDecimal) o).multiply(new BigDecimal(100)).intValue() + "");
            } else if (o instanceof Number || o instanceof Boolean || o instanceof Character) {
                ret.add(o.toString());
            } else if (o instanceof Collection) {
                ret.add(fromCollection((Collection) o));
            } else if (o.getClass().isArray()) {
                ret.add(fromArray(o));
            } else if (o instanceof Date || o instanceof String) {
                ret.add(o);
            } else {
                ret.add(fromObject(o));
            }
        }
        return ret;
    }

    // public static void main(String[] args) throws Exception {
    // System.out.println(Modifier.TRANSIENT);
    // System.out.println(Modifier.PRIVATE);
    // System.out.println(Modifier.PROTECTED);
    // System.out.println(Modifier.PUBLIC);
    // System.out.println(Modifier.STATIC);
    // System.out.println(Modifier.FINAL);
    // Class clazz = Person.class;
    // Field[] fields = clazz.getDeclaredFields();
    // for (Field field : fields) {
    // System.out.print(field.getName() + "->");
    // System.out.println(Modifier.isTransient(field.getModifiers()));
    // }
    // }
    //
    // static class Person {
    // transient String password;
    // private transient String pwd;
    // private List<Integer> ids;
    // Date bir = new Date();
    // private static final Integer PI=3;
    // int[] array = new int[] { 1, 2, 3 };
    //
    // public List<Integer> getIds() {
    // return ids;
    // }
    //
    // public void setIds(List<Integer> ids) {
    // this.ids = ids;
    // }
    //
    // public Date getBir() {
    // return bir;
    // }
    //
    // public void setBir(Date bir) {
    // this.bir = bir;
    // }
    //
    // public int[] getArray() {
    // return array;
    // }
    //
    // public void setArray(int[] array) {
    // this.array = array;
    // }
    //
    // public String getPassword() {
    // return password;
    // }
    //
    // public void setPassword(String password) {
    // this.password = password;
    // }
    //
    // }
}
